From bc3ba6864174a905d095a3a57a2cb0889d229d9e Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Thu, 12 Jan 2017 23:20:31 +0100 Subject: [PATCH] snapshot: Add gtk_snapshot_push_blend() and use it for backgrounds. --- docs/reference/gtk/gtk4-sections.txt | 1 + gtk/gtkrenderbackground.c | 75 ++++++----------------- gtk/gtksnapshot.c | 91 ++++++++++++++++++++++++++++ gtk/gtksnapshot.h | 5 ++ gtk/gtksnapshotprivate.h | 4 ++ 5 files changed, 120 insertions(+), 56 deletions(-) diff --git a/docs/reference/gtk/gtk4-sections.txt b/docs/reference/gtk/gtk4-sections.txt index 13a4b0d30b..76fb07966c 100644 --- a/docs/reference/gtk/gtk4-sections.txt +++ b/docs/reference/gtk/gtk4-sections.txt @@ -4459,6 +4459,7 @@ gtk_snapshot_push_repeat gtk_snapshot_push_clip gtk_snapshot_push_rounded_clip gtk_snapshot_push_cross_fade +gtk_snapshot_push_blend gtk_snapshot_pop gtk_snapshot_pop_and_append gtk_snapshot_set_transform diff --git a/gtk/gtkrenderbackground.c b/gtk/gtkrenderbackground.c index e52d1de3b7..6d2f2fd953 100644 --- a/gtk/gtkrenderbackground.c +++ b/gtk/gtkrenderbackground.c @@ -619,6 +619,8 @@ gtk_css_style_snapshot_background (GtkCssStyle *style, gint idx; GtkCssValue *background_image; GtkCssValue *box_shadow; + GtkCssValue *blend_modes; + GskBlendMode blend_mode; const GdkRGBA *bg_color; gint number_of_layers; @@ -639,71 +641,32 @@ gtk_css_style_snapshot_background (GtkCssStyle *style, snapshot, &bg.boxes[GTK_CSS_AREA_BORDER_BOX]); - /* - * When we have a blend mode set for the background, we must blend on a transparent - * background. GSK can't do that yet. - */ - if (_gtk_theming_background_needs_push_group (style)) - { - GtkCssValue *blend_modes; - GskBlendMode blend_mode; + blend_modes = gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BACKGROUND_BLEND_MODE); + number_of_layers = _gtk_css_array_value_get_n_values (background_image); - blend_modes = gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BACKGROUND_BLEND_MODE); + for (idx = number_of_layers - 1; idx >= 0; idx--) + { + blend_mode = _gtk_css_blend_mode_value_get (_gtk_css_array_value_get_nth (blend_modes, idx)); - gtk_snapshot_push (snapshot, TRUE, "BackgroundBlendGroup"); + if (blend_mode != GSK_BLEND_MODE_DEFAULT) + gtk_snapshot_push_blend (snapshot, blend_mode, "Background<%u>Blend<%u>", idx, blend_mode); + } - gtk_theming_background_snapshot_color (&bg, snapshot, bg_color, background_image); + gtk_theming_background_snapshot_color (&bg, snapshot, bg_color, background_image); - number_of_layers = _gtk_css_array_value_get_n_values (background_image); + for (idx = number_of_layers - 1; idx >= 0; idx--) + { + blend_mode = _gtk_css_blend_mode_value_get (_gtk_css_array_value_get_nth (blend_modes, idx)); - for (idx = number_of_layers - 1; idx >= 0; idx--) + if (blend_mode == GSK_BLEND_MODE_DEFAULT) { - blend_mode = _gtk_css_blend_mode_value_get (_gtk_css_array_value_get_nth (blend_modes, idx)); - - if (blend_mode == GSK_BLEND_MODE_DEFAULT) - { - gtk_theming_background_snapshot_layer (&bg, idx, snapshot); - } - else - { - GskRenderNode *bottom, *top, *blend; - - bottom = gtk_snapshot_pop (snapshot); - - gtk_snapshot_push (snapshot, TRUE, "BackgroundBlendGroup", blend_mode); - gtk_theming_background_snapshot_layer (&bg, idx, snapshot); - top = gtk_snapshot_pop (snapshot); - - /* XXX: Is this necessary? Do we need a NULL node? */ - if (top == NULL) - top = gsk_container_node_new (NULL, 0); - if (bottom == NULL) - bottom = gsk_container_node_new (NULL, 0); - - blend = gsk_blend_node_new (bottom, top, blend_mode); - if (snapshot->record_names) - gsk_render_node_set_name (blend, "BackgroundBlend"); - - gtk_snapshot_push (snapshot, TRUE, "BackgroundBlendGroup"); - gtk_snapshot_append_node (snapshot, blend); - - gsk_render_node_unref (blend); - gsk_render_node_unref (top); - gsk_render_node_unref (bottom); - } + gtk_theming_background_snapshot_layer (&bg, idx, snapshot); } - - gtk_snapshot_pop_and_append (snapshot); - } - else - { - gtk_theming_background_snapshot_color (&bg, snapshot, bg_color, background_image); - - number_of_layers = _gtk_css_array_value_get_n_values (background_image); - - for (idx = number_of_layers - 1; idx >= 0; idx--) + else { + gtk_snapshot_pop_and_append (snapshot); gtk_theming_background_snapshot_layer (&bg, idx, snapshot); + gtk_snapshot_pop_and_append (snapshot); } } diff --git a/gtk/gtksnapshot.c b/gtk/gtksnapshot.c index d79f9039c1..3e0b9f4e0c 100644 --- a/gtk/gtksnapshot.c +++ b/gtk/gtksnapshot.c @@ -675,6 +675,97 @@ gtk_snapshot_push_shadow (GtkSnapshot *snapshot, snapshot->state = state; } +static GskRenderNode * +gtk_snapshot_collect_blend_top (GtkSnapshotState *state, + GskRenderNode **nodes, + guint n_nodes, + const char *name) +{ + GskRenderNode *bottom_node, *top_node, *blend_node; + + top_node = gtk_snapshot_collect_default (state, nodes, n_nodes, name); + bottom_node = state->data.blend.bottom_node; + + /* XXX: Is this necessary? Do we need a NULL node? */ + if (top_node == NULL) + top_node = gsk_container_node_new (NULL, 0); + if (bottom_node == NULL) + bottom_node = gsk_container_node_new (NULL, 0); + + blend_node = gsk_blend_node_new (bottom_node, top_node, state->data.blend.blend_mode); + gsk_render_node_set_name (blend_node, name); + + gsk_render_node_unref (top_node); + gsk_render_node_unref (bottom_node); + + return blend_node; +} + +static GskRenderNode * +gtk_snapshot_collect_blend_bottom (GtkSnapshotState *state, + GskRenderNode **nodes, + guint n_nodes, + const char *name) +{ + state->parent->data.blend.bottom_node = gtk_snapshot_collect_default (state, nodes, n_nodes, name); + + return NULL; +} + +/** + * gtk_snapshot_push_blend: + * @snapshot: a #GtkSnapshot + * @blend_mode: blend mode to use + * @name: printf format string for name of the pushed node + * @...: printf-style arguments for the @name string + * + * Blends together 2 images with the given blend mode. + * + * Until the first call to gtk_snapshot_pop(), the bottom image for the + * blend operation will be recorded. After that call, the top image to + * be blended will be recorded until the second call to gtk_snapshot_pop(). + * + * Calling this function requires 2 subsequent calls to gtk_snapshot_pop(). + **/ +void +gtk_snapshot_push_blend (GtkSnapshot *snapshot, + GskBlendMode blend_mode, + const char *name, + ...) +{ + GtkSnapshotState *state; + char *str; + + if (name && snapshot->record_names) + { + va_list args; + + va_start (args, name); + str = g_strdup_vprintf (name, args); + va_end (args); + } + else + str = NULL; + + state = gtk_snapshot_state_new (snapshot->state, + str, + snapshot->state->clip_region, + snapshot->state->translate_x, + snapshot->state->translate_y, + gtk_snapshot_collect_blend_top); + state->data.blend.blend_mode = blend_mode; + state->data.blend.bottom_node = NULL; + + state = gtk_snapshot_state_new (state, + str, + state->clip_region, + state->translate_x, + state->translate_y, + gtk_snapshot_collect_blend_bottom); + + snapshot->state = state; +} + static GskRenderNode * gtk_snapshot_collect_cross_fade_end (GtkSnapshotState *state, GskRenderNode **nodes, diff --git a/gtk/gtksnapshot.h b/gtk/gtksnapshot.h index 7ac7a43481..b59f32ce58 100644 --- a/gtk/gtksnapshot.h +++ b/gtk/gtksnapshot.h @@ -80,6 +80,11 @@ void gtk_snapshot_push_shadow (GtkSnapshot const char *name, ...) G_GNUC_PRINTF (4, 5); GDK_AVAILABLE_IN_3_90 +void gtk_snapshot_push_blend (GtkSnapshot *snapshot, + GskBlendMode blend_mode, + const char *name, + ...) G_GNUC_PRINTF (3, 4); +GDK_AVAILABLE_IN_3_90 void gtk_snapshot_push_cross_fade (GtkSnapshot *snapshot, double progress, const char *name, diff --git a/gtk/gtksnapshotprivate.h b/gtk/gtksnapshotprivate.h index 3989bc5fde..3676a10859 100644 --- a/gtk/gtksnapshotprivate.h +++ b/gtk/gtksnapshotprivate.h @@ -67,6 +67,10 @@ struct _GtkSnapshotState { GskShadow *shadows; GskShadow a_shadow; /* Used if n_shadows == 1 */ } shadow; + struct { + GskBlendMode blend_mode; + GskRenderNode *bottom_node; + } blend; struct { double progress; GskRenderNode *start_node; -- 2.30.2